package com.zjh.workflow.flowable.service.impl;

import com.zjh.common.exception.ServiceException;
import com.zjh.workflow.flowable.entity.ProcessDefineList;
import com.zjh.workflow.flowable.service.ProcessService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProcessServiceImpl implements ProcessService {

    @Resource
    ProcessEngine processEngine;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Override
    public String getProcessDefinitionXmlStrByProcessId(String processDefinitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        BpmnXMLConverter converter = new BpmnXMLConverter();
        byte[] bytes = converter.convertToXML(bpmnModel);

        return new String(bytes, StandardCharsets.UTF_8);
    }

    @Override
    public String getProcessDefinitionXmlStrByProcessInstanceId(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        return getProcessDefinitionXmlStrByProcessId(processInstance.getProcessDefinitionId());
    }

    /**
     * 通过文件部署工作流
     *
     * @param flowName
     * @param file
     */
    @Override
    public Deployment deployFlowViaMultiFile(String flowName, MultipartFile file) {

        DeploymentBuilder deploymentBuilder = null;
        try {
            deploymentBuilder = repositoryService.createDeployment()
                    .name(flowName)
                    .addInputStream(file.getOriginalFilename(), file.getInputStream());
        } catch (IOException e) {
            throw new ServiceException(e);
        }

        Deployment deployment = deploymentBuilder.deploy();

        return deployment;
    }


    /**
     * 获取所有已部署流程的最新版本列表
     *
     * @return List<ProcessDefineList>
     */
    @Override
    public List<ProcessDefineList> getAllLatestProcessDefinitions() {
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .list();

        return processDefinitions.stream()
                .map(pd -> new ProcessDefineList(
                        pd.getName(),
                        pd.getKey(),
                        pd.getId(),
                        pd.getVersion()))
                .collect(Collectors.toList());
    }


    @Override
    public Boolean deleteDeployByProcessKey(String processKey) {

        // 获取原始的流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processKey)
                .latestVersion()
                .singleResult();

        if (processDefinition != null) {
            String deploymentId = processDefinition.getDeploymentId();
            // 删除旧的部署
            repositoryService.deleteDeployment(deploymentId, true);
            return true;
        } else {
            log.error("Process definition not found.");
            return false;
        }

    }

    @Override
    public Boolean deleteDeployByProcessId(String processId) {
        // 获取原始的流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processId)
                .latestVersion()
                .singleResult();

        if (processDefinition != null) {
            String deploymentId = processDefinition.getDeploymentId();
            // 删除旧的部署
            repositoryService.deleteDeployment(deploymentId, true);
            return true;
        } else {
            log.error("Process definition not found.");
            return false;
        }
    }

}
